const { User, ExpRecord } = require('../db');

// 等级配置
const levelConfig = [
  { level: 1, name: '见习观察者', minExp: 0, maxExp: 100 },
  { level: 2, name: '初级浏览者', minExp: 100, maxExp: 300 },
  { level: 3, name: '活跃用户', minExp: 300, maxExp: 600 },
  { level: 4, name: '内容鉴赏者', minExp: 600, maxExp: 1000 },
  { level: 5, name: '资深评鉴员', minExp: 1000, maxExp: 2000 },
  { level: 6, name: '优质创作者', minExp: 2000, maxExp: 4000 },
  { level: 7, name: '专业顾问', minExp: 4000, maxExp: 7000 },
  { level: 8, name: '领域达人', minExp: 7000, maxExp: 10000 },
  { level: 9, name: '首席品鉴官', minExp: 10000, maxExp: 15000 },
  { level: 10, name: '内容总监', minExp: 15000, maxExp: 20000 },
  { level: 11, name: '社区导师', minExp: 20000, maxExp: 30000 },
  { level: 12, name: '平台专家', minExp: 30000, maxExp: 50000 },
  { level: 13, name: '资深院士', minExp: 50000, maxExp: 80000 },
  { level: 14, name: '荣誉理事', minExp: 80000, maxExp: 120000 },
  { level: 15, name: '终身成就者', minExp: 120000, maxExp: Infinity }
];

// 经验值规则配置
const expRules = {
  login: { value: 10, dailyLimit: 10, description: '每日登录' },
  post: { value: 20, dailyLimit: 100, description: '发布内容' },
  comment: { value: 5, dailyLimit: 50, description: '发表评论' },
  like: { value: 2, dailyLimit: 20, description: '点赞内容' },
  share: { value: 5, dailyLimit: 25, description: '分享内容' },
  beingLiked: { value: 2, dailyLimit: 40, description: '内容被点赞' },
  beingFavorited: { value: 5, dailyLimit: 50, description: '内容被收藏' },
  beingCommented: { value: 3, dailyLimit: 30, description: '内容被评论' },
  beingShared: { value: 3, dailyLimit: 30, description: '内容被分享' },
  focusUser: { value: 50, dailyLimit: 50, description: '成为焦点用户' }
};

// 每日经验值上限
let DAILY_EXP_LIMIT = 50;

// 计算等级信息
const calculateLevelInfo = (totalExp) => {
  // 查找当前等级
  let currentLevel = levelConfig[0];
  for (let i = levelConfig.length - 1; i >= 0; i--) {
    if (totalExp >= levelConfig[i].minExp) {
      currentLevel = levelConfig[i];
      break;
    }
  }

  // 计算下一级所需经验（注意：level从1开始，数组索引从0开始）
  const nextLevel = currentLevel.level < levelConfig.length ? levelConfig[currentLevel.level] : currentLevel;
  const currentLevelExp = totalExp - currentLevel.minExp;
  // 对于非最高等级，levelExpNeeded应该是当前等级的满级经验
  const levelExpNeeded = currentLevel.maxExp - currentLevel.minExp;

  // 计算经验百分比
  const expPercentage = currentLevel.level === levelConfig.length
    ? 100
    : Math.min(Math.floor((currentLevelExp / levelExpNeeded) * 100), 100);

  // 对于最高等级，显示总经验；其他等级显示当前等级内的经验
  const displayCurrentExp = currentLevel.level === levelConfig.length ? totalExp : currentLevelExp;
  const displayNextLevelExp = currentLevel.level === levelConfig.length ? totalExp : levelExpNeeded;

  // 返回等级信息
  return {
    level: currentLevel.level,
    name: currentLevel.name, 
    iconUrl: `/images/level-${currentLevel.level}.png`,
    currentExp: displayCurrentExp,
    nextLevelExp: displayNextLevelExp,
    expPercentage: expPercentage
  };
};

// 检查每日经验值限制并重置（如果是新的一天）
const checkAndResetDailyExp = async (user) => {
  // 获取当前日期的零点
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  // 获取最后更新日期的零点
  const lastUpdate = new Date(user.expInfo.lastUpdateDate || new Date());
  lastUpdate.setHours(0, 0, 0, 0);

  // 如果最后更新日期不是今天，重置每日经验值
  if (lastUpdate < today) {
    user.expInfo.dailyExp = 0;
    user.expInfo.lastUpdateDate = new Date();
    return true; // 表示已重置
  }
  
  return false; // 表示未重置
};

// 获取用户经验信息
const getUserExpInfo = async (openid) => {
  try {
    const user = await User.findOne({ openid });
    if (!user) {
      return null;
    }

    // 初始化expInfo对象（如果不存在）
    if (!user.expInfo) {
      user.expInfo = {
        totalExp: 0,
        dailyExp: 0,
        dailyExpLimit: DAILY_EXP_LIMIT,
        level: 1,
        levelName: '见习观察者',
        lastUpdateDate: new Date()
      };
      await user.save();
    }

    // 检查并重置每日经验值（如果是新的一天）
    const isReset = await checkAndResetDailyExp(user);
    if (isReset) {
      await user.save();
    }

    // 同步每日上限配置变更
    if (user.expInfo.dailyExpLimit !== DAILY_EXP_LIMIT) {
      user.expInfo.dailyExpLimit = DAILY_EXP_LIMIT;
    }

    // 计算等级信息
    const levelInfo = calculateLevelInfo(user.expInfo.totalExp);

    // 更新用户等级名称或上限变更（如果有变化）
    if (
      user.expInfo.level !== levelInfo.level ||
      user.expInfo.levelName !== levelInfo.name ||
      user.expInfo.dailyExpLimit !== DAILY_EXP_LIMIT
    ) {
      user.expInfo.level = levelInfo.level;
      user.expInfo.levelName = levelInfo.name;
      await user.save();
    }

    return {
      expInfo: user.expInfo,
      levelInfo
    };
  } catch (error) {
    console.error('获取用户经验信息失败:', error);
    throw error;
  }
};

// 记录经验值（带并发保护，防止超过当日上限）
const recordExp = async (openid, type, customValue = null) => {
  try {
    const rule = expRules[type];
    if (!rule && customValue === null) throw new Error(`未知的经验值类型: ${type}`);

    const expValue = customValue !== null ? customValue : rule.value;

    // 读取用户
    let user = await User.findOne({ openid });
    if (!user) throw new Error(`用户不存在: ${openid}`);

    // 初始化expInfo
    if (!user.expInfo) {
      user.expInfo = {
        totalExp: 0,
        dailyExp: 0,
        dailyExpLimit: DAILY_EXP_LIMIT,
        level: 1,
        levelName: '见习观察者',
        lastUpdateDate: new Date()
      };
      await user.save();
    }

    // 重置每日经验（跨天）
    const isReset = await checkAndResetDailyExp(user);
    if (isReset) await user.save();

    // 计算当日类型剩余额度
    let remainingType = Infinity;
    if (rule) {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      const records = await ExpRecord.find({ openid, type, createdAt: { $gte: today } });
      const todayTypeExp = records.reduce((sum, r) => sum + r.value, 0);
      remainingType = Math.max(0, rule.dailyLimit - todayTypeExp);
    }

    // 计算当日总剩余额度（基于当前读取的 user）
    const remainingDaily = Math.max(0, DAILY_EXP_LIMIT - (user.expInfo.dailyExp || 0));
    let allowed = Math.max(0, Math.min(expValue, remainingType, remainingDaily));

    if (allowed <= 0) {
      return {
        expAdded: 0,
        expInfo: user.expInfo,
        levelInfo: calculateLevelInfo(user.expInfo.totalExp || 0),
        levelUp: false,
        limitReached: true
      };
    }

    // 乐观锁式重试，防并发超限
    const maxRetries = 3;
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      // 基于当前读到的值计算要更新后的总经验
      const baseDaily = user.expInfo.dailyExp || 0;
      const baseTotal = user.expInfo.totalExp || 0;
      const newDaily = baseDaily + allowed;
      const newTotal = baseTotal + allowed;
      // 计算等级
      const levelInfo = calculateLevelInfo(newTotal);

      const updateRes = await User.updateOne(
        { _id: user._id, 'expInfo.dailyExp': baseDaily, 'expInfo.totalExp': baseTotal },
        {
          $inc: { 'expInfo.dailyExp': allowed, 'expInfo.totalExp': allowed },
          $set: {
            'expInfo.lastUpdateDate': new Date(),
            'expInfo.level': levelInfo.level,
            'expInfo.levelName': levelInfo.name,
            'expInfo.dailyExpLimit': DAILY_EXP_LIMIT
          }
        }
      );

      if (updateRes && updateRes.modifiedCount === 1) {
        // 成功写入，创建记录
        await ExpRecord.create({
          openid,
          type,
          value: allowed,
          description: rule ? rule.description : '自定义经验值',
          createdAt: new Date()
        });

        // 读取最新用户用于返回
        const latest = await User.findOne({ openid });
        return {
          expAdded: allowed,
          expInfo: latest.expInfo,
          levelInfo: calculateLevelInfo(latest.expInfo.totalExp || 0),
          levelUp: (user.expInfo.level || 1) < (latest.expInfo.level || 1),
          limitReached: allowed < expValue
        };
      }

      // 并发冲突：重新读取用户与剩余额度，缩减 allowed 后重试
      user = await User.findOne({ openid });
      const remainingNow = Math.max(0, DAILY_EXP_LIMIT - (user.expInfo.dailyExp || 0));
      allowed = Math.max(0, Math.min(allowed, remainingNow));
      if (allowed <= 0) break;
    }

    // 到这里代表本次没有可用额度
    return {
      expAdded: 0,
      expInfo: user.expInfo,
      levelInfo: calculateLevelInfo(user.expInfo.totalExp || 0),
      levelUp: false,
      limitReached: true
    };
  } catch (error) {
    console.error('记录经验值失败:', error);
    throw error;
  }
};

// 每日重置所有用户的每日经验值（定时任务调用）
const resetAllUsersDailyExp = async () => {
  try {
    const result = await User.updateMany(
      {},
      { 
        $set: {
          'expInfo.dailyExp': 0,
          'expInfo.lastUpdateDate': new Date()
        } 
      }
    );
    console.log(`已重置 ${result.modifiedCount} 名用户的每日经验值`);
    return result;
  } catch (error) {
    console.error('重置用户每日经验值失败:', error);
    throw error;
  }
};

// 获取等级配置
const getLevelConfig = () => {
  return levelConfig;
};

// 获取经验值规则
const getExpRules = () => {
  return expRules;
};

// 更新经验值规则
const updateExpRule = async (type, value, dailyLimit) => {
  try {
    // 检查规则是否存在
    if (!expRules[type]) {
      return {
        success: false,
        message: `未知的经验值类型: ${type}`
      };
    }
    
    // 检查参数合法性
    if (value < 0 || dailyLimit < 0) {
      return {
        success: false,
        message: '经验值和每日上限不能为负数'
      };
    }
    
    // 更新规则
    expRules[type].value = value;
    expRules[type].dailyLimit = dailyLimit;
    
    return {
      success: true,
      data: expRules[type]
    };
  } catch (error) {
    console.error('更新经验值规则失败:', error);
    return {
      success: false,
      message: error.message || '更新经验值规则失败'
    };
  }
};

// 更新每日经验值上限
const updateDailyExpLimit = async (value) => {
  try {
    // 检查参数合法性
    if (value <= 0) {
      return {
        success: false,
        message: '每日上限必须是正数'
      };
    }
    
    // 更新全局每日经验值上限
    DAILY_EXP_LIMIT = value;
    
    return {
      success: true,
      data: { dailyExpLimit: DAILY_EXP_LIMIT }
    };
  } catch (error) {
    console.error('更新每日经验值上限失败:', error);
    return {
      success: false,
      message: error.message || '更新每日经验值上限失败'
    };
  }
};

// 清理过期的经验记录
const cleanupOldExpRecords = async (daysToKeep = 0) => {
  try {
    // 计算截止时间：今天0点往前 daysToKeep 天
    const cutoff = new Date();
    cutoff.setHours(0, 0, 0, 0);
    if (daysToKeep && Number.isFinite(daysToKeep)) {
      cutoff.setDate(cutoff.getDate() - daysToKeep);
    }
    const result = await ExpRecord.deleteMany({ createdAt: { $lt: cutoff } });
    console.log(`清理过期经验记录完成，删除 ${result.deletedCount || 0} 条，截止时间: ${cutoff.toISOString()}`);
    return result;
  } catch (error) {
    console.error('清理过期经验记录失败:', error);
    throw error;
  }
};

module.exports = {
  calculateLevelInfo,
  getUserExpInfo,
  recordExp,
  resetAllUsersDailyExp,
  levelConfig,
  expRules,
  getLevelConfig,
  getExpRules,
  updateExpRule,
  updateDailyExpLimit,
  cleanupOldExpRecords
}; 